﻿/*
 * User: artem
 * Date: 02.05.2011
 * Time: 13:01
 * 
 */
using System;
using System.Collections.Generic;
using System.Data.SQLite;

using SettingManager;

using OOExp = Kernel.OpenOrganizerException;
using OOECode = Kernel.OpenOrganizerException.ErrorCode;	

namespace Kernel
{
	/// <summary>
	/// Класс баз данных. Реализует интерфейсы для 
	/// клиента и демона.
	/// </summary>
	public sealed class DataBase : IDBClient, IDBDemon
	{ 
		/// <summary>
		/// конфиг для базы, там должны храниться все запросы и
		/// строки соединения.
		/// </summary>
		const string data_base_config = @"DataBase.conf";
		
		/// <summary>
		/// Конфиг ридер.
		/// </summary>
		private readonly XMLSettingManager settings = null;
		
		/// <summary>
		/// Соединение с базой.
		/// </summary>
		private SQLiteConnection connection = null;
		
		private int current_id;
		
		/// <summary>
		/// Реализация синглетона
		/// </summary>
		
		private static DataBase instance = new DataBase();
		
		public static DataBase Instance 
		{
			get {	return instance;	}
		}
		
		private DataBase()
		{
            try
            {
                settings = XMLSettingManager.Load(data_base_config);

                connection = new SQLiteConnection(settings[@"ConnectionString"]);

                connection.Open();
                
                SQLiteCommand command = connection.CreateCommand();
                command.CommandText = settings[@"LoadIdQuery"];
                
                using (SQLiteDataReader reader = command.ExecuteReader())
                {
                	if (reader.Read() &&
                	    !reader.IsDBNull(0))
                		current_id = reader.GetInt32(0);
                	else
                		current_id = 0;
                }
            }
            catch (Exception exp)
            { throw new OOExp(OOECode.DateBaseConnectError, exp); }
		}
		
		/// <summary>
		/// Реализация интерфейса для клиента.
		/// IDBClient
		/// </summary>
		
		int IDBClient.AddEvent(Event event_obj)
		{
            try
            {
                Event.AssertEvent(event_obj);

                SQLiteCommand command = connection.CreateCommand();
                command.CommandText = settings[@"AddEventQuery"];
                command.Parameters.AddWithValue(@"@id", ++current_id);
                command.Parameters.AddWithValue(@"@title", event_obj.Title);
                command.Parameters.AddWithValue(@"@description", event_obj.Description);
                command.Parameters.AddWithValue(@"@date", event_obj.Date);
                command.Parameters.AddWithValue(@"@start", event_obj.NotificationStart);
                command.Parameters.AddWithValue(@"@end", event_obj.NotificationEnd);
                command.Parameters.AddWithValue(@"@count", event_obj.NotificationCount);
                command.Parameters.AddWithValue(@"@type", (int)event_obj.Type);
                command.Parameters.AddWithValue(@"@periodicity", (int)event_obj.Periodicity);

                command.ExecuteNonQuery();

                event_obj.ID = current_id;

                return current_id;
            }
            catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
		}
		
		void IDBClient.UpdateEvent(Event event_obj)
		{
			try
			{
				SQLiteCommand command = connection.CreateCommand();
				command.CommandText = settings[@"UpdateEventQuery"];
				command.Parameters.AddWithValue(@"@id", event_obj.ID);
				command.Parameters.AddWithValue(@"@title", event_obj.Title);
				command.Parameters.AddWithValue(@"@description", event_obj.Description);
				command.Parameters.AddWithValue(@"@date", event_obj.Date);
				command.Parameters.AddWithValue(@"@start", event_obj.NotificationStart);
				command.Parameters.AddWithValue(@"@end", event_obj.NotificationEnd);
				command.Parameters.AddWithValue(@"@count", event_obj.NotificationCount);
				command.Parameters.AddWithValue(@"@type", event_obj.Type.ToString());
				command.Parameters.AddWithValue(@"@periodicity", event_obj.Periodicity.ToString());
				
				command.ExecuteNonQuery();
			}
			catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
		}
		
		void IDBClient.RemoveEvent(int id_event)
		{
			try
			{
				SQLiteCommand command = connection.CreateCommand();
				command.CommandText = settings["RemoveEventQuery"];
				command.Parameters.AddWithValue(@"@id", id_event);
				command.ExecuteNonQuery();
			}
			catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
		}
		
		List<Event> IDBClient.GetEvents(DateTime from,
		                                DateTime to)
		{
			try
			{
				SQLiteCommand command = connection.CreateCommand();
				command.CommandText = settings["GetEventsQuery"];
				command.Parameters.AddWithValue(@"@from", from);
				command.Parameters.AddWithValue(@"@to", to);

                using (SQLiteDataReader reader = command.ExecuteReader())
                    return ReadEvent(reader);
			}
			catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
		}
		
		Event IDBClient.GetEvent(int id_event)
		{
			try
			{
				SQLiteCommand command = connection.CreateCommand();
				command.CommandText = settings["GetEventQuery"];
				command.Parameters.AddWithValue(@"@id", id_event);
				
				object[] row = null;
				using (SQLiteDataReader reader = command.ExecuteReader())
				{
                    row = new object[reader.FieldCount];
					reader.Read();
					reader.GetValues(row);
				}
				
				return new Event(row);
			}
			catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
		}
		
		///<summary
		/// Реализация инрфеса бд для демона
		///</summary

        List<Event> IDBDemon.GetEventsForNotifications()
        {
            return (this as IDBClient).GetEvents(DateTime.Now,
                                                 DateTime.Now + new TimeSpan(24, 0, 0));
        }

        Event IDBDemon.GetEvent(int id)
        {
            return (this as IDBClient).GetEvent(id);
        }

        List<Event> IDBService.GetPastEvents()
        {
            try
            {
                SQLiteCommand command = connection.CreateCommand();
                command.CommandText = settings[@"GetPastEventQuery"];
                command.Parameters.AddWithValue(@"@now", DateTime.Now);

                using (SQLiteDataReader reader = command.ExecuteReader())
                    return ReadEvent(reader);
            }
            catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
        }

        void IDBService.ExtendEvent(int id,
                                    DateTime extended_time,
                                    DateTime extended_notification_start,
                                    DateTime extended_notification_end)
        {
            try
            {
                SQLiteCommand command = connection.CreateCommand();
                command.CommandText = settings[@"ExtendEventQuery"];
                command.Parameters.AddWithValue(@"@date", extended_time);
                command.Parameters.AddWithValue(@"@start", extended_notification_start);
                command.Parameters.AddWithValue(@"@end", extended_notification_end);
                command.Parameters.AddWithValue(@"@id", id);

                command.ExecuteNonQuery();
            }
            catch (Exception exp)
            { throw new OOExp(OOECode.FailDataBaseOperation, exp); }
        }



        private List<Event> ReadEvent(SQLiteDataReader reader)
        {
            List<Event> result = new List<Event>();

            object[] row = new object[reader.FieldCount];
            while (reader.Read())
            {
                reader.GetValues(row);
                result.Add(new Event(row));
            }

            return result;
        }
	}
}
